﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using Flux.Data;
using Flux.Data.Maps;
using Flux.Editor.Extensions;
using Flux.Editor.Messaging;

namespace Flux.Editor.Controls
{
	public partial class ProjectExplorer
	{
		#region Properties

		public static readonly DependencyProperty ProjectProperty = DependencyProperty.Register("Project", typeof (Project), typeof (ProjectExplorer), new PropertyMetadata(OnProjectChange));
		public Project Project
		{
			get { return (Project) GetValue(ProjectProperty); }
			set { SetValue(ProjectProperty, value); }
		}

		#endregion

		#region Initialization

		public ProjectExplorer()
		{
			InitializeComponent();
			if (this.IsInDesignMode()) return;
			App.Messenger.Register(Tokens.RefreshProjectExplorer, Refresh);
		}

		#endregion

		#region Change Events

		private static void OnProjectChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var projectExplorer = (ProjectExplorer) d;
			projectExplorer.Refresh();
		}

		#endregion

		#region Actions

		public void Refresh(object message = null)
		{
			projectTree.Items.Clear();

			var root = CreateLeaf(Project.Name, "/Resources\\FluxProject.png", Project);
			var maps = CreateLeaf("Maps", "/Resources\\FluxFolder.png");
			var content = CreateLeaf("Content", "/Resources\\FluxFolder.png");

			AddMaps(maps);
			AddContent(content);

			root.Items.Add(maps);
			root.Items.Add(content);
			
			projectTree.Items.Add(root);

			projectTree.SelectedItemChanged += TreeSelectedItemChanged;
		}

		#endregion

		#region Methods

		private void AddMaps(TreeViewItem mapRoot)
		{
			foreach (var map in Project.Maps)
			{
				var mapLeaf = CreateLeaf(map.Name, "/Resources\\FluxFile.png", map);
				mapLeaf.MouseLeftButtonUp += MapLeafOnMouseLeftButtonUp;
				mapRoot.Items.Add(mapLeaf);

				foreach (var layer in map.Layers)
				{
					var layerLeaf = CreateLeaf(layer.Name, "/Resources\\FluxFile.png", layer);
					mapLeaf.Items.Add(layerLeaf);
				}
			}
		}
		
		private void AddContent(TreeViewItem contentRoot)
		{
			var tilesets = CreateLeaf("Tilesets", "/Resources\\FluxFolder.png");

			AddTilesets(tilesets);

			contentRoot.Items.Add(tilesets);
		}

		private void AddTilesets(TreeViewItem tilesetsRoot)
		{
			foreach (var tileset in Project.Tilesets)
			{
				var tilesetLeaf = CreateLeaf(tileset.Name, "/Resources\\FluxFile.png", tileset);
				tilesetsRoot.Items.Add(tilesetLeaf);
			}
		}
		
		private TreeViewItem CreateLeaf(string header, string iconUri, object associatedObject = null)
		{
			var panel = new StackPanel
			{
				Orientation = Orientation.Horizontal
			};
			var img = new Image
			{
				Source = new BitmapImage(new Uri(iconUri, UriKind.RelativeOrAbsolute))
			};
			var text = new TextBlock
			{
				Text = header,
				Margin = new Thickness(4, 0, 0, 0)
			};
			panel.Children.Add(img);
			panel.Children.Add(text);

			var ret = new TreeViewItem
			{
				Header = panel,
				IsExpanded = true,
				Tag = associatedObject,
				ContextMenu = CreateContextMenu(header, associatedObject)
			};

			return ret;
		}

		private ContextMenu CreateContextMenu(string header, object associatedObject)
		{
			var ret = new ContextMenu();

			if (associatedObject == null)
			{
				switch (header)
				{
					case "Maps":
						ret.Items.Add(CreateContextMenuItem("Add New Map", Tokens.AddNewMap));
						ret.Items.Add(CreateContextMenuItem("Add Existing Map", Tokens.AddExistingMap));
						break;
					case "Tilesets":
						ret.Items.Add(CreateContextMenuItem("Add New Tileset", Tokens.AddNewTileset));
						break;
				}
			}
			else
			{
				if (associatedObject is Project)
				{
					return null;	
				}
			}

			return ret;
		}

		private TextBlock CreateContextMenuItem(string header, Tokens messageToken)
		{
			var ret = new TextBlock
			{
				Text = header,
				Tag = messageToken
			};
			ret.MouseLeftButtonDown += (s, e) => App.Messenger.Send(((TextBlock)s).Tag, s);
			return ret;
		}
		
		#endregion

		#region Events

		private void TreeSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
		{
			var tree = (TreeView)sender;
			var selectedItem = (TreeViewItem)tree.SelectedItem;
			if (selectedItem == null) return;
			App.Messenger.Send(Tokens.SetSelectedObject, selectedItem.Tag);
		}

		private void MapLeafOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
		{
			var leaf = (TreeViewItem) sender;
			var map = (Map) leaf.Tag;
			App.Messenger.Send(Tokens.SetActiveMap, map);
		}

		#endregion
	}
}